﻿using AutoMapper;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NewRetail.Application.Components.Platform;
using NewRetail.Application.Components.Platform.Entity;
using NewRetail.Application.Components.WeChat.CardVoucher.Entity;
using NewRetail.Application.Components.WeChat.CardVoucher.Model;
using NewRetail.Application.Components.WeChat.Configurations;
using NewRetail.Application.Components.WeChat.Services.HttpClients;
using NewRetail.Application.Components.WeChat.TemplateMessage.Model;
using NewRetail.Application.Components.WeChat.TemplateMessage.Services;
using NewRetail.Application.Core.Entity;
using SKIT.FlurlHttpClient.Wechat.Api.Models;
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Events;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Uow;
using NewRetail.Application.Utility;
using NewRetail.Application.Core;
using System.Threading;

namespace NewRetail.Application.Components.WeChat.CardVoucher.Services
{
    /// <summary>
    /// 卡券服务。
    /// </summary>
    public interface ICardVoucherService : IApplicationService
    {
        /// <summary>
        /// 创建代金券批次
        /// </summary>
        /// <param name="inputData"></param>
        /// <returns></returns>
        Task<(string, string)> CreateMarketingFavorStockAsync(MarketingFavorStockCreateInputDto inputData);
        /// <summary>
        /// 激活代金券批次
        /// </summary>
        /// <param name="inputData"></param>
        /// <returns></returns>
        Task<(string, string)> ActiveMarketingFavorStockAsync(MarketingFavorStockActiveInputDto inputData);
        /// <summary>
        /// 发放代金券批次
        /// </summary>
        /// <param name="inputData"></param>
        /// <returns></returns>
        Task<(string, string)> SendMarketingFavorStockAsync(MarketingFavorStockSendInputDto inputData);
        /// <summary>
        /// 条件查询批次列表
        /// </summary>
        /// <param name="inputData"></param>
        /// <returns></returns>
        Task<QueryMarketingFavorStocksResponse> QueryMarketingFavorStockAsync(MarketingFavorStockQueryInputDto inputData);
        /// <summary>
        /// 查询批次详情
        /// </summary>
        /// <param name="stockCreatorMerchantId"></param>
        /// <param name="stockId"></param>
        /// <returns></returns>
        Task<GetMarketingFavorStockByStockIdResponse> GetMarketingFavorStockByStockIdAsync(string stockCreatorMerchantId, string stockId);
        /// <summary>
        /// 添加代金券批次(将商户后台生成的券保存在库里以备后续使用)
        /// </summary>
        /// <param name="stockId"></param>
        /// <returns></returns>
        Task<(CardVoucherInfo, string)> SaveOffLineMarketingFavorStockAsync(string stockId);
        /// <summary>
        /// 查询代金券详情
        /// </summary>
        /// <param name="couponId"></param>
        /// <param name="openId"></param>
        /// <param name="appId"></param>
        /// <returns></returns>
        Task<GetMarketingFavorUserCouponByCouponIdResponse> GetMarketingFavorUserCouponsAsync(string couponId, string openId, string appId = null);
        /// <summary>
        /// 更新券使用后的状态
        /// </summary>
        /// <param name="wechatTenpayEvent"></param>
        /// <param name="merchantId"></param>
        /// <returns></returns>
        Task<bool> UpdataUserCoupons(WechatTenpayEvent wechatTenpayEvent, string merchantId);
        /// <summary>
        /// 根据商户号、openid查用户的券
        /// </summary>
        /// <param name="stockId"></param>
        /// <param name="openId"></param>
        /// <param name="appId"></param>
        /// <returns></returns>
        Task<QueryMarketingFavorUserCouponsResponse> QueryMarketingFavorUserCouponsAsync(string openId, string appId = null, string stockId = null);
        /// <summary>
        /// 根据openid查用户的券并修改本地状态
        /// </summary>
        /// <param name="merchantId"></param>
        /// <param name="openId"></param>
        /// <param name="appId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        Task<(List<string>, string)> QuerySaveMarketingFavorUserCouponsAsync(string openId, string appId = null, string merchantId = null, CancellationToken cancellationToken = default(CancellationToken));
        /// <summary>
        /// 查询代金券批次及领用详情信息(弃用,使用QueryMarketingFavorAllUserCouponsAsync)
        /// </summary>
        /// <param name="stockId"></param>
        /// <param name="openId"></param>
        /// <param name="appId"></param>
        /// <returns></returns>
        Task<List<LocalMarketingFavorStockUserCouponsDto>> QueryLocalMarketingFavorAllUserCouponsAsync(string openId, string appId = null, string stockId = null);
        /// <summary>
        /// 查询代金券批次及领用详情信息
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        Task<(List<MarketingFavorStockUserCouponsDto>, string, bool)> QueryMarketingFavorAllUserCouponsAsync(MarketingFavorStockUserCouponsInputDto inputDto);
        /// <summary>
        /// 查询结果追加券详情
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        Task<CardVoucherIntegralInfo[]> AttachCardVoucher(CardVoucherIntegralInfo[] data);
    }

    /// <summary>
    /// 卡券服务实现。
    /// </summary>
    public class CardVoucherService : ApplicationService, ICardVoucherService
    {
        #region Field

        private readonly ILogger _logger;
        private readonly IHttpContextAccessor _accessor;
        private readonly IWechatTenpayHttpClientFactory _wechatTenpayHttpClientFactory;
        //private readonly IMapper _mapper;
        private readonly WxpayOptions _wechatPayOptions;
        private readonly IRepository<CardVoucherInfo> _cardVoucherRepository;
        private readonly IRepository<UserCouponsInfo> _userCouponsRepository;
        private readonly IRepository<CardVoucherIntegralInfo> _cardVoucherIntegralRepository;
        private readonly IRepository<PosMember> _posMemberRepository;
        private readonly IRepository<PosIntegral> _posIntegralRepository;
        protected IEntityHelper _entityHelper => this.LazyServiceProvider.LazyGetRequiredService<IEntityHelper>();
        protected INoGeneratorService _noGeneratorService => this.LazyServiceProvider.LazyGetRequiredService<INoGeneratorService>();
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        public readonly ITemplateMessageService _templateMessageService;
        #endregion Field

        #region Constructor

        public CardVoucherService(IHttpContextAccessor accessor, IWechatTenpayHttpClientFactory wechatTenpayHttpClientFactory,
            IRepository<CardVoucherInfo> cardVoucherRepository, IOptions<WxpayOptions> wechatPayOptions,/*IMapper mapper,*/
            IRepository<UserCouponsInfo> userCouponsRepository, IUnitOfWorkManager unitOfWorkManager,
            IRepository<CardVoucherIntegralInfo> cardVoucherIntegralRepository, IRepository<PosMember> posMemberRepository,
            IRepository<PosIntegral> posIntegralRepository,
            ITemplateMessageService templateMessageService, ILogger<CardVoucherService> logger)
        {
            _accessor = accessor;
            _wechatTenpayHttpClientFactory = wechatTenpayHttpClientFactory;
            _cardVoucherRepository = cardVoucherRepository;
            _userCouponsRepository = userCouponsRepository;
            _cardVoucherIntegralRepository = cardVoucherIntegralRepository;
            _posMemberRepository = posMemberRepository;
            _posIntegralRepository = posIntegralRepository;
            _unitOfWorkManager = unitOfWorkManager;
            //_mapper = mapper;
            _logger = logger;
            _wechatPayOptions = wechatPayOptions.Value;
            _templateMessageService = templateMessageService;
        }

        #endregion Constructor

        #region Implementation

        #region 创建代金券批次
        /// <summary>
        /// 创建代金券批次
        /// </summary>
        /// <returns></returns>
        public async Task<(string, string)> CreateMarketingFavorStockAsync(MarketingFavorStockCreateInputDto inputData)
        {
            var stockId = "";
            var merchantId = inputData.MerchantId;
            var wechatTenpayClient = _wechatTenpayHttpClientFactory.Create(merchantId);
            var reqTempNo = await _noGeneratorService.GenerateGeneralNoAsync("_CV_");
            var outRequestNo = string.Concat(merchantId, reqTempNo, DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff"));//merchantId + "_TEST_ORN_" + DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff");
            var requestData = new CreateMarketingFavorStockRequest()
            {
                StockName = inputData.StockName,
                BelongMerchantId = merchantId,
                Comment = inputData.Comment,
                AvailableBeginTime = inputData.AvailableBeginTime,//DateTime.Parse("2021-11-11T12:00:00+08:00"),// 
                AvailableEndTime = inputData.AvailableEndTime,//DateTime.Parse("2021-11-12T12:00:00+08:00"),// 
                StockUseRule = new CreateMarketingFavorStockRequest.Types.StockUseRule()
                {
                    MaxCoupons = inputData.MaxCoupons,
                    MaxAmount = inputData.MaxAmount,
                    MaxAmountPerDay = inputData.MaxAmountPerDay,
                    MaxCouponsPerUser = inputData.MaxCouponsPerUser,
                    IsNaturalPersonLimit = inputData.IsNaturalPersonLimit,
                    IsPreventApiAbuse = inputData.IsPreventApiAbuse
                },
                Pattern = new CreateMarketingFavorStockRequest.Types.Pattern()
                {
                    Description = inputData.Description,
                    BackgroundColor = inputData.BackgroundColor
                },
                CouponUseRule = new CreateMarketingFavorStockRequest.Types.CouponUseRule()
                {
                    NormalCoupon = new CreateMarketingFavorStockRequest.Types.CouponUseRule.Types.NormalCoupon()
                    {
                        CouponAmount = inputData.CouponAmount,
                        TransactionMinimum = inputData.TransactionMinimum
                    },
                    AllowCombineUse = inputData.AllowCombineUse,
                    AvailableMerchantIdList = inputData.AvailableMerchantIdList,//new List<string>() { merchantId },
                    TradeTypeList = inputData.TradeTypeList,
                },
                IsNoCash = inputData.IsNoCash,
                StockType = inputData.StockType,
                OutRequestNumber = outRequestNo
            };

            var responseInfo = await wechatTenpayClient.ExecuteCreateMarketingFavorStockAsync(requestData, cancellationToken: _accessor.HttpContext.RequestAborted);
            if (!responseInfo.IsSuccessful())
            {
                _logger.LogWarning(
                    "创建代金券失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                    responseInfo.RawStatus, responseInfo.ErrorCode, responseInfo.ErrorMessage
                );
            }
            else
            {
                stockId = responseInfo.StockId;
                //创建成功则插入数据库
                //如果批次号不存在则插入
                var cardVoucher = new CardVoucherInfo()
                {
                    stockId = stockId,
                    stockName = inputData.StockName,
                    stockType = inputData.StockType,
                    availableBeginTime = inputData.AvailableBeginTime.ToString("yyyy-MM-ddTHH:mm:ssK"),
                    availableEndTime = inputData.AvailableEndTime.ToString("yyyy-MM-ddTHH:mm:ssK"),
                    outRequestNo = outRequestNo,
                    noCash = inputData.IsNoCash,
                    maxCoupons = inputData.MaxCoupons,
                    maxAmount = inputData.MaxAmount,
                    maxAmountByDay = inputData.MaxAmountPerDay,
                    maxCouponsPerUser = inputData.MaxCouponsPerUser,
                    naturalPersonLimit = inputData.IsNaturalPersonLimit,
                    preventApiAbuse = inputData.IsPreventApiAbuse,
                    isActive = false,
                    cardStatus= "unactivated",
                    distributedCoupons = 0
                };
                var saveFlag = await SaveCardVoucher(cardVoucher);
                if(!saveFlag)
                {
                    stockId = "";
                    responseInfo.ErrorMessage = "券创建成功，保存失败！";
                }
                //var db = await _cardVoucherRepository.GetDbContextAsync();
                //var cardVoucher = await db.Set<CardVoucherInfo>().AsNoTracking().FirstOrDefaultAsync(x => x.stockId == stockId);
                //if (cardVoucher == null)
                //{
                    
                //    _entityHelper.InitEntity(cardVoucher);
                //    await _cardVoucherRepository.InsertAsync(cardVoucher, autoSave: true);
                //}
            }
            

            return (stockId, responseInfo.ErrorMessage);
        }
        #endregion

        #region 激活代金券批次
        /// <summary>
        /// 激活代金券批次
        /// </summary>
        /// <returns></returns>
        public async Task<(string, string)> ActiveMarketingFavorStockAsync(MarketingFavorStockActiveInputDto inputData)
        {
            var startTime = "";
            var stockId = inputData.StockId;
            var merchantId = inputData.MerchantId;
            var stockCreatorMchid = inputData.StockCreatorMchid;
            //如果不指定将使用商户号
            if (string.IsNullOrEmpty(stockCreatorMchid))
                stockCreatorMchid = merchantId;
            var wechatTenpayClient = _wechatTenpayHttpClientFactory.Create(merchantId);
            var requestData = new StartMarketingFavorStockRequest()
            {
                StockId = stockId,
                StockCreatorMerchantId = stockCreatorMchid
            };
            var responseInfo = await wechatTenpayClient.ExecuteStartMarketingFavorStockAsync(requestData, cancellationToken: _accessor.HttpContext.RequestAborted);
            if (!responseInfo.IsSuccessful())
            {
                _logger.LogWarning(
                    "激活代金券失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                    responseInfo.RawStatus, responseInfo.ErrorCode, responseInfo.ErrorMessage
                );
            }
            else
            {
                stockId = responseInfo.StockId;
                var db = await _cardVoucherRepository.GetDbContextAsync();
                var cardVoucher = await db.Set<CardVoucherInfo>().AsNoTracking().FirstOrDefaultAsync(x => x.stockId == stockId);
                if (cardVoucher != null)
                {
                    //如果批次号存在则更新激活状态
                    cardVoucher.isActive = true;
                    await _cardVoucherRepository.UpdateAsync(cardVoucher, autoSave: true);
                }
            }
            startTime = string.IsNullOrEmpty(responseInfo.StockId) ? "" : responseInfo.StartTime.ToString();
            
            return (startTime, responseInfo.ErrorMessage);
        }
        #endregion

        #region 发放代金券批次
        /// <summary>
        /// 发放代金券批次
        /// </summary>
        /// <returns></returns>
        public async Task<(string, string)> SendMarketingFavorStockAsync(MarketingFavorStockSendInputDto inputData)
        {
            var errMsg = "";
            var couponId = "";
            var stockId = inputData.StockId;
            var merchantId = inputData.MerchantId;
            var stockCreatorMchid = inputData.StockCreatorMerchantId;
            var appId = inputData.AppId;
            var openId = inputData.OpenId;
            //同一个人如果要领取多张，那么此值一定不能重复
            var outRequestNo = inputData.OutRequestNumber;
            //openId为空则不作操作
            if(string.IsNullOrEmpty(openId))
                return (couponId, "openId不能为空！");

            //校验用户积分是否够兑换券
            var dbPosMember = await _posMemberRepository.GetDbContextAsync();
            var posMember = await dbPosMember.Set<PosMember>().AsNoTracking().FirstOrDefaultAsync(x => x.openId == openId);
            var dbPosIntegral = await _posIntegralRepository.GetDbContextAsync();
            var cardVoucherIntegral = await dbPosIntegral.Set<CardVoucherIntegralInfo>().AsNoTracking().FirstOrDefaultAsync(x => x.stockId == stockId);
            if (posMember != null)
            {
                //如果积分不足则不允许兑换
                if (posMember.integral < cardVoucherIntegral.integral)
                    return (couponId, "积分不足！");
            }
            else
                return (couponId, "用户不存在,请先领取会员卡！");

            //appId为null则默认获取配置第一个
            if (string.IsNullOrEmpty(appId))
                appId = _wechatPayOptions.Merchants?.FirstOrDefault().AppId;
            //商户号不指定，那么获取配置第一个
            if (string.IsNullOrEmpty(merchantId))
                merchantId = _wechatPayOptions.Merchants?.FirstOrDefault().MerchantId;
            //如果不指定将使用商户号
            if (string.IsNullOrEmpty(stockCreatorMchid))
                stockCreatorMchid = merchantId;
            var wechatTenpayClient = _wechatTenpayHttpClientFactory.Create(merchantId);
            var requestData = new SendMarketingFavorUserCouponRequest()
            {
                StockId = stockId,
                AppId = appId,
                OutRequestNumber = outRequestNo,
                OpenId = inputData.OpenId,
                StockCreatorMerchantId = stockCreatorMchid
            };
            var responseInfo = await wechatTenpayClient.ExecuteSendMarketingFavorUserCouponAsync(requestData, cancellationToken: _accessor.HttpContext.RequestAborted);
            if (!responseInfo.IsSuccessful())
            //if (responseInfo.IsSuccessful())
            {
                errMsg = responseInfo.ErrorMessage;
                _logger.LogWarning(
                    "发放代金券失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                    responseInfo.RawStatus, responseInfo.ErrorCode, responseInfo.ErrorMessage
                );
            }
            else
            {
                couponId = responseInfo.CouponId;
                //测试
                //couponId = "29968113215";
                //发放成功则需要相应的增加库里的已发券数量，且将领取人的券进行保存
                var db = await _cardVoucherRepository.GetDbContextAsync();
                var cardVoucher = await db.Set<CardVoucherInfo>().AsNoTracking().FirstOrDefaultAsync(x => x.stockId == stockId);
                if (cardVoucher != null)
                {
                    //批次存在则需要将领取人的券进行保存
                    var dbUserCoupons = await _userCouponsRepository.GetDbContextAsync();
                    var userCoupons = await dbUserCoupons.Set<UserCouponsInfo>().AsNoTracking().FirstOrDefaultAsync(x => x.stockId == stockId && x.outRequestNo == outRequestNo && x.couponId == couponId && x.openId == openId);

                    using var uow = _unitOfWorkManager.Begin(requiresNew: true, isTransactional: true);
                    try
                    {
                        //券领取人不存在则插入
                        if (userCoupons == null)
                        {
                            //暂时不调用查询代金券详情API获取更多信息进行存储
                            userCoupons = new UserCouponsInfo()
                            {
                                outRequestNo = outRequestNo,
                                openId = openId,
                                stockId = stockId,
                                couponId = couponId
                            };
                            //保存券
                            _entityHelper.InitEntity(userCoupons);
                            await _userCouponsRepository.InsertAsync(userCoupons);
                            //更新券批次
                            cardVoucher.distributedCoupons++;
                            cardVoucher.updateTime = DateTime.Now;
                            _entityHelper.SetUpdationInfo(cardVoucher);
                            await _cardVoucherRepository.UpdateAsync(cardVoucher);

                            //会员积分表记录增加
                            var posMemberIntegral = new PosIntegral()
                            {
                                memberID = posMember.Id,
                                integralSource = "积分兑换券",
                                plusOrMinus = false,
                                integral = cardVoucherIntegral.integral.ObjToDecimal(),
                                orderNo = outRequestNo,
                                operateTime = DateTime.Now
                            };
                            _entityHelper.InitEntity(posMemberIntegral);
                            await _posIntegralRepository.InsertAsync(posMemberIntegral);
                            //会员表的积分更新
                            posMember.integral = posMember.integral - cardVoucherIntegral.integral.ObjToInt();
                            posMember.updateTime = DateTime.Now;
                            _entityHelper.SetUpdationInfo(posMember);
                            await _posMemberRepository.UpdateAsync(posMember);

                            #region 发送积分兑换券模板消息
                            var couponAmount = cardVoucher.couponAmount/100;
                            var msgContent = $"亲爱的会员朋友,您已成功兑换{couponAmount}元的代金劵,即日起在门店消费结账时将自动扣减，感谢您的支持。";
                            var resultId = await SendIntegralExchangeMessage(openId, cardVoucherIntegral.integral.ToString());// msgContent);
                            if(string.IsNullOrEmpty(resultId))
                                _logger.LogWarning("发送积分兑换券通知失败！");
                            #endregion
                        }
                        await uow.CompleteAsync();
                    }
                    catch(Exception e)
                    {
                        errMsg = e.Message;
                        await uow.RollbackAsync();
                        _logger.LogError(message: e.Message, exception: e);
                    }
                }                   
            }
            //couponId = responseInfo.CouponId;
            return (couponId, errMsg);
        }
        #endregion

        #region 条件查询批次列表
        /// <summary>
        /// 条件查询批次列表
        /// </summary>
        /// <param name="inputData"></param>
        /// <returns></returns>
        public async Task<QueryMarketingFavorStocksResponse> QueryMarketingFavorStockAsync(MarketingFavorStockQueryInputDto inputData)
        {
            var result = new QueryMarketingFavorStocksResponse();
            var merchantId = inputData.StockCreatorMchid;
            var wechatTenpayClient = _wechatTenpayHttpClientFactory.Create(merchantId);
            try
            {
                var requestData = new QueryMarketingFavorStocksRequest()
                {
                    Offset = inputData.Offset,
                    Limit = inputData.Limit,
                    StockCreatorMerchantId = merchantId
                };
                var responseInfo = await wechatTenpayClient.ExecuteQueryMarketingFavorStocksAsync(requestData, cancellationToken: _accessor.HttpContext.RequestAborted);
                if (!responseInfo.IsSuccessful())
                {
                    _logger.LogWarning(
                        "查询代金券失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                        responseInfo.RawStatus, responseInfo.ErrorCode, responseInfo.ErrorMessage
                    );
                }
                result = responseInfo;
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message);
            }
            return result;
        }
        #endregion

        #region 查询批次详情
        /// <summary>
        /// 查询批次详情
        /// </summary>
        /// <param name="stockCreatorMerchantId"></param>
        /// <param name="stockId"></param>
        /// <returns></returns>
        public async Task<GetMarketingFavorStockByStockIdResponse> GetMarketingFavorStockByStockIdAsync(string stockCreatorMerchantId, string stockId)
        {
            //商户号不指定，那么获取配置第一个
            if (string.IsNullOrEmpty(stockCreatorMerchantId))
                stockCreatorMerchantId = _wechatPayOptions.Merchants?.FirstOrDefault().MerchantId;

            var result = new GetMarketingFavorStockByStockIdResponse();
            var wechatTenpayClient = _wechatTenpayHttpClientFactory.Create(stockCreatorMerchantId);
            try
            {
                var requestData = new GetMarketingFavorStockByStockIdRequest()
                {
                    StockId = stockId,
                    StockCreatorMerchantId = stockCreatorMerchantId
                };
                var responseInfo = await wechatTenpayClient.ExecuteGetMarketingFavorStockByStockIdAsync(requestData, cancellationToken: _accessor.HttpContext.RequestAborted);
                if (!responseInfo.IsSuccessful())
                {
                    _logger.LogWarning(
                        "查询代金券批次详情失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                        responseInfo.RawStatus, responseInfo.ErrorCode, responseInfo.ErrorMessage
                    );
                }
                result = responseInfo;
            }
            catch (Exception e)
            {
                result.ErrorMessage = e.Message;
                _logger.LogError(e.Message);
            }
            return result;
        }
        #endregion

        #region 添加代金券批次(将商户后台生成的券保存在库里以备后续使用)
        /// <summary>
        /// 添加代金券批次(将商户后台生成的券保存在库里以备后续使用)
        /// </summary>
        /// <param name="stockId"></param>
        /// <returns></returns>
        public async Task<(CardVoucherInfo, string)> SaveOffLineMarketingFavorStockAsync(string stockId)
        {
            var errMsg = "";
            var cardVoucher = new CardVoucherInfo();
            var result = await GetMarketingFavorStockByStockIdAsync(null, stockId);
            if(result.IsSuccessful())
            {
                //成功则保存代金券批次
                cardVoucher.stockId = stockId;
                cardVoucher.stockName = result.StockName;
                cardVoucher.availableBeginTime = result.AvailableBeginTime.ToString("yyyy-MM-ddTHH:mm:ssK");
                cardVoucher.availableEndTime = result.AvailableEndTime.ToString("yyyy-MM-ddTHH:mm:ssK");
                cardVoucher.stockType = result.StockType;
                cardVoucher.noCash = result.IsNoCash;
                cardVoucher.maxCoupons = result.StockUseRule.MaxCoupons;
                cardVoucher.maxAmount = result.StockUseRule.MaxAmount;
                cardVoucher.maxAmountByDay = result.StockUseRule.MaxAmountPerDay;
                cardVoucher.maxCouponsPerUser = result.StockUseRule.MaxCouponsPerUser;
                cardVoucher.couponAmount = result.StockUseRule.NormalCoupon.CouponAmount;
                cardVoucher.cardStatus = result.Status;
                cardVoucher.distributedCoupons = result.DistributedCoupons;
                //保存
                var saveFlag = await SaveCardVoucher(cardVoucher);
                if (!saveFlag)
                    errMsg = "保存失败！";
            }
            else
            {
                //不成功返回错误信息
                errMsg = result.ErrorMessage;
            }
            return (cardVoucher, errMsg);
        }
        #endregion

        #region 查询代金券详情
        /// <summary>
        /// 查询代金券详情
        /// </summary>
        /// <param name="couponId"></param>
        /// <param name="openId"></param>
        /// <param name="appId"></param>
        /// <returns></returns>
        public async Task<GetMarketingFavorUserCouponByCouponIdResponse> GetMarketingFavorUserCouponsAsync(string couponId, string openId, string appId = null)
        {
            var merchantId = "";
            //appid不指定，那么获取配置第一个
            if (string.IsNullOrEmpty(appId))
                appId = _wechatPayOptions.Merchants?.FirstOrDefault().AppId;
            //商户号不指定，那么获取配置第一个
            if (string.IsNullOrEmpty(merchantId))
                merchantId = _wechatPayOptions.Merchants?.FirstOrDefault().MerchantId;

            var result = new GetMarketingFavorUserCouponByCouponIdResponse();
            var wechatTenpayClient = _wechatTenpayHttpClientFactory.Create(merchantId);
            try
            {
                var requestData = new GetMarketingFavorUserCouponByCouponIdRequest()
                {
                    CouponId = couponId,
                    AppId = appId,
                    OpenId = openId
                };
                var responseInfo = await wechatTenpayClient.ExecuteGetMarketingFavorUserCouponByCouponIdAsync(requestData, cancellationToken: _accessor.HttpContext.RequestAborted);
                if (!responseInfo.IsSuccessful())
                {
                    _logger.LogWarning(
                        "查询代金券详情失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                        responseInfo.RawStatus, responseInfo.ErrorCode, responseInfo.ErrorMessage
                    );
                }
                result = responseInfo;
            }
            catch (Exception e)
            {
                result.ErrorMessage = e.Message;
                _logger.LogError(e.Message);
            }
            return result;
        }
        #endregion

        #region 更新券使用后的状态
        /// <summary>
        /// 更新券使用后的状态
        /// </summary>
        /// <param name="wechatTenpayEvent"></param>
        /// <param name="merchantId"></param>
        /// <returns></returns>
        public async Task<bool> UpdataUserCoupons(WechatTenpayEvent wechatTenpayEvent, string merchantId)
        {
            var result = false;
            wechatTenpayEvent.Should().NotBeNull();
            var wechatTenpayClient = _wechatTenpayHttpClientFactory.Create(merchantId);
            //解密resource
            var decResource = wechatTenpayClient.DecryptEventResource<MarketingFavorCouponResource>(wechatTenpayEvent);
            //更新数据
            var couponId = decResource.CouponId;
            var couponStatus = decResource.Status;
            var couponType = decResource.CouponType;
            var stockId = decResource.StockId;
            //从库里获取券记录
            var dbUserCoupons = await _userCouponsRepository.GetDbContextAsync();
            var userCoupons = await dbUserCoupons.Set<UserCouponsInfo>().AsNoTracking().FirstOrDefaultAsync(x => x.stockId == stockId && x.couponId == couponId);
            if (userCoupons != null)
            {
                //券存在则需要更新状态
                userCoupons.couponStatus = couponStatus;
                userCoupons.couponType = couponType;
                _entityHelper.SetUpdationInfo(userCoupons);
                await _userCouponsRepository.UpdateAsync(userCoupons, autoSave: true);
                result = true;
            }

            return result;
        }
        #endregion

        #region 根据商户号、openid查用户的券(只能查出除过期以外所有状态的用户券)
        /// <summary>
        /// 根据商户号、openid查用户的券(只能查出除过期以外所有状态的用户券)
        /// </summary>
        /// <param name="stockId"></param>
        /// <param name="openId"></param>
        /// <param name="appId"></param>
        /// <returns></returns>
        public async Task<QueryMarketingFavorUserCouponsResponse> QueryMarketingFavorUserCouponsAsync(string openId, string appId = null, string stockId = null)
        {
            var merchantId = "";
            //appid不指定，那么获取配置第一个
            if (string.IsNullOrEmpty(appId))
                appId = _wechatPayOptions.Merchants?.FirstOrDefault().AppId;
            //商户号不指定，那么获取配置第一个
            if (string.IsNullOrEmpty(merchantId))
                merchantId = _wechatPayOptions.Merchants?.FirstOrDefault().MerchantId;

            var result = new QueryMarketingFavorUserCouponsResponse();
            var wechatTenpayClient = _wechatTenpayHttpClientFactory.Create(merchantId);
            try
            {
                var requestData = new QueryMarketingFavorUserCouponsRequest()
                {
                    CreatorMerchantId = merchantId,
                    AppId = appId,
                    OpenId = openId
                };
                var responseInfo = await wechatTenpayClient.ExecuteQueryMarketingFavorUserCouponsAsync(requestData, cancellationToken: _accessor.HttpContext.RequestAborted);
                if (!responseInfo.IsSuccessful())
                {
                    _logger.LogWarning(
                        "根据商户号、openid查用户的券失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                        responseInfo.RawStatus, responseInfo.ErrorCode, responseInfo.ErrorMessage
                    );
                }
                result = responseInfo;
            }
            catch (Exception e)
            {
                result.ErrorMessage = e.Message;
                _logger.LogError(e.Message);
            }
            return result;
        }
        #endregion

        #region 根据openid查用户的券并修改本地状态
        /// <summary>
        /// 根据openid查用户的券并修改本地状态
        /// </summary>
        /// <param name="merchantId"></param>
        /// <param name="openId"></param>
        /// <param name="appId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<(List<string>, string)> QuerySaveMarketingFavorUserCouponsAsync(string openId, string appId = null, string merchantId = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            var result = new List<string>();
            var errCouponId = new List<string>();
            var errMsg = "";            
            //appid不指定，那么获取配置第一个
            if (string.IsNullOrEmpty(appId))
                appId = _wechatPayOptions.Merchants?.FirstOrDefault().AppId;
            //商户号不指定，那么获取配置第一个
            if (string.IsNullOrEmpty(merchantId))
                merchantId = _wechatPayOptions.Merchants?.FirstOrDefault().MerchantId;

            using var uow = _unitOfWorkManager.Begin(requiresNew: true, isTransactional: true);
            try
            {
                //从库里获取券记录
                var dbUserCoupons = await _userCouponsRepository.GetDbContextAsync();
                var userCoupons = await dbUserCoupons.Set<UserCouponsInfo>().AsNoTracking().Where(x => x.openId == openId && string.IsNullOrEmpty(x.couponStatus))?.ToListAsync();
                if (userCoupons != null)
                {
                    var wechatTenpayClient = _wechatTenpayHttpClientFactory.Create(merchantId);
                    //找到对应记录则更新相应状态
                    foreach (var item in userCoupons)
                    {
                        var couponId = item.couponId;
                        var requestData = new GetMarketingFavorUserCouponByCouponIdRequest()
                        {
                            CouponId = couponId,
                            AppId = appId,
                            OpenId = openId
                        };
                        var responseInfo = await wechatTenpayClient.ExecuteGetMarketingFavorUserCouponByCouponIdAsync(requestData, cancellationToken: _accessor?.HttpContext?.RequestAborted ?? cancellationToken);
                        if (!responseInfo.IsSuccessful())
                        {
                            errCouponId.Add(couponId);
                            _logger.LogWarning(
                                "保存查询代金券详情失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                                responseInfo.RawStatus, responseInfo.ErrorCode, responseInfo.ErrorMessage
                            );
                        }
                        else
                        {
                            result.Add(couponId);
                            var couponStatus = responseInfo.Status;
                            //只更新已实扣或已使用和过期的券
                            if (couponStatus == "USED" || couponStatus == "EXPIRED")
                            {
                                //读取成功则将记录状态更新
                                item.couponStatus = responseInfo.Status;
                                item.couponType = responseInfo.CouponType;
                                _entityHelper.SetUpdationInfo(item);
                                await _userCouponsRepository.UpdateAsync(item);
                            }
                        }
                    }

                    await dbUserCoupons.SaveChangesAsync();

                    await uow.CompleteAsync();
                }

                errMsg = string.Join(",", errCouponId);
            }
            catch (Exception e)
            {
                await uow.RollbackAsync();
                errMsg = e.Message;
                _logger.LogError(message: e.Message, exception: e);
            }
            return (result, errMsg);
        }
        #endregion

        #region 查询代金券批次及领用详情信息(弃用,使用QueryMarketingFavorAllUserCouponsAsync)
        /// <summary>
        /// 查询代金券批次及领用详情信息
        /// </summary>
        /// <param name="stockId"></param>
        /// <param name="openId"></param>
        /// <param name="appId"></param>
        /// <returns></returns>
        public async Task<List<LocalMarketingFavorStockUserCouponsDto>> QueryLocalMarketingFavorAllUserCouponsAsync(string openId, string appId = null, string stockId = null)
        {
            //var merchantId = "";
            ////appid不指定，那么获取配置第一个
            //if (string.IsNullOrEmpty(appId))
            //    appId = _wechatPayOptions.Merchants?.FirstOrDefault().AppId;
            ////商户号不指定，那么获取配置第一个
            //if (string.IsNullOrEmpty(merchantId))
            //    merchantId = _wechatPayOptions.Merchants?.FirstOrDefault().MerchantId;

            var result = new List<LocalMarketingFavorStockUserCouponsDto>();
            try
            {
                var dbCardVoucher = await _cardVoucherRepository.GetDbContextAsync();
                //var dbUserCoupons = await _userCouponsRepository.GetDbContextAsync();
                //从库里获取批次记录
                var cardVoucher = await dbCardVoucher.Set<CardVoucherInfo>().AsNoTracking()?.ToListAsync();
                //从库里获取券记录                
                var userCoupons = await dbCardVoucher.Set<UserCouponsInfo>().AsNoTracking()?.ToListAsync();
                //从库里获取会员记录
                var posMembers = await dbCardVoucher.Set<PosMember>().AsNoTracking()?.ToListAsync();

                var cvuc = cardVoucher.GroupJoin(userCoupons, c => c.stockId, u => u.stockId,
                    (cv, uc) => new { cv, uc }).DefaultIfEmpty();
                var cardVoucher_userCoupons = cvuc.Select((p, uc) => new LocalMarketingFavorStockUserCouponsDto()
                {
                    StockId = p.cv.stockId,
                    OutRequestNo = p.cv.outRequestNo,
                    StockName = p.cv.stockName,
                    AvailableBeginTime = p.cv.availableBeginTime.ObjToDate().ToString("yyyy-MM-dd HH:mm:ss"),
                    AvailableEndTime = p.cv.availableEndTime.ObjToDate().ToString("yyyy-MM-dd HH:mm:ss"),
                    MaxCouponsPerUser = p.cv.maxCouponsPerUser,
                    MaxCoupons = p.cv.maxCoupons,
                    DistributedCoupons = p.cv.distributedCoupons,
                    CouponAmount = p.cv.couponAmount,
                    CouponList = p.uc.Select(x => new LocalMarketingFavorStockUserCouponsDto.Types.Coupon
                    {
                        CouponId = x.couponId,
                        OpenId = x.openId,
                        CouponStatus = string.IsNullOrEmpty(x.couponStatus) || x.couponStatus == "SENDED" ? "可用" : x.couponStatus == "USED" ? "已使用" : x.couponStatus == "EXPIRED" ? "已过期" : "未知",
                        MemberNo = posMembers.FirstOrDefault(m => m.openId == x.openId)?.No ?? "未知",
                        MemberName = posMembers.FirstOrDefault(m => m.openId == x.openId)?.memberName ?? "未知",
                        MemberTel = posMembers.FirstOrDefault(m => m.openId == x.openId)?.memberTel ?? "未知"
                    }).ToList()
                }).ToList();

                //var cardVoucher_userCoupons = cardVoucher.GroupJoin(userCoupons, c => c.stockId, u => u.stockId,
                //    (cv, uc) => new { cv, uc })
                //    .SelectMany(p => p.uc.DefaultIfEmpty(),
                //    (p, uc) => new /* LocalMarketingFavorStockUserCouponsDto()*/
                //    {
                //        id = p.cv.Id,
                //        si=uc.couponId
                //        //OutRequestNo=p.o.outRequestNo,
                //        //StockName=p.o.stockName,
                //        //AvailableBeginTime=p.o.availableBeginTime,
                //        //AvailableEndTime=p.o.availableEndTime,
                //        //MaxCouponsPerUser=p.o.maxCouponsPerUser,
                //        //MaxCoupons=p.o.maxCoupons,
                //        //DistributedCoupons=p.o.distributedCoupons,
                //        //CouponAmount = p.o.couponAmount,
                //        //CouponList=p.u.Select(x=>new Types.Coupon 
                //        //{ 
                //        //    CouponId=x.couponId,
                //        //    OpenId=x.openId,
                //        //    CouponStatus=x.couponStatus
                //        //}).ToList()
                //    }).ToList();

                result = cardVoucher_userCoupons;
            }
            catch (Exception e)
            {
                //result.ErrorMessage = e.Message;
                _logger.LogError(e.Message);
            }
            return result;
        }
        #endregion

        #region 查询代金券批次及领用详情信息
        /// <summary>
        /// 查询代金券批次及领用详情信息
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        public async Task<(List<MarketingFavorStockUserCouponsDto>, string, bool)> QueryMarketingFavorAllUserCouponsAsync(MarketingFavorStockUserCouponsInputDto inputDto)
        {
            var openId = inputDto.OpenId;
            var telOrNo = inputDto.TelOrNo;
            var beginDate = inputDto.BeginDate;
            var endDate = inputDto.EndDate;
            var stockId = inputDto.StockId;
            var errorMessage = "";
            var couponStatus = inputDto.CouponStatus;
            var isLastPage = false;
            var pageIndex = inputDto.Page;
            var pageSize = inputDto.PageSize;
            var result = new List<MarketingFavorStockUserCouponsDto>();
            
            try
            {
                var dbCardVoucher = await _cardVoucherRepository.GetDbContextAsync();
                var dbUserCoupons = await _userCouponsRepository.GetDbContextAsync();
                //从库里获取批次记录
                var cardVoucher = await dbCardVoucher.Set<CardVoucherInfo>().AsNoTracking()?.ToListAsync();
                //从库里获取券记录                
                var userCoupons = await dbCardVoucher.Set<UserCouponsInfo>().AsNoTracking()?.ToListAsync();
                //从库里获取会员记录                
                var posMembers = await dbCardVoucher.Set<PosMember>().AsNoTracking()?.ToListAsync();
                //过滤openId
                if (!string.IsNullOrEmpty(openId))
                    posMembers = posMembers.Where(x => x.openId != null && x.openId.Contains(openId)).ToList();
                //过滤电话或会员号
                if (!string.IsNullOrEmpty(telOrNo))
                    posMembers = posMembers.Where(x => (x.memberTel != null && x.memberTel.Contains(telOrNo)) || (x.No != null && x.No.Contains(telOrNo))).ToList();
                //过滤券Id
                if (!string.IsNullOrEmpty(stockId))
                    cardVoucher = cardVoucher.Where(x => x.stockId != null && x.stockId.Contains(stockId)).ToList();
                //过滤发券日期
                if (!string.IsNullOrEmpty(beginDate) || !string.IsNullOrEmpty(endDate))
                    userCoupons = userCoupons.Where(x => x.addTime?.ToString("yyyy-MM-dd").CompareTo(beginDate) >= 0 && x.addTime?.ToString("yyyy-MM-dd").CompareTo(endDate) <= 0).ToList();
                ////根据券状态过滤
                //if (!string.IsNullOrEmpty(couponStatus))
                //{
                //    switch (couponStatus)
                //    {
                //        case "0":
                //            userCoupons = userCoupons.Where(x => string.IsNullOrEmpty(x.couponStatus) || x.couponStatus == "SENDED").ToList();
                //            break;
                //        case "1":
                //            userCoupons = userCoupons.Where(x => x.couponStatus == "USED" || x.couponStatus == "EXPIRED").ToList();
                //            break;
                //        default:
                //            break;
                //    }
                //}
                    

                //获取券和发放关联
                var cardVoucherUserCoupons = cardVoucher.GroupJoin(userCoupons, c => c.stockId, u => u.stockId, (c, u) => new { c, u })
                    .SelectMany(p => p.u.DefaultIfEmpty(), (p, u) => new MarketingFavorStockUserCouponsDto()
                    {
                        StockId = p.c.stockId,
                        StockOutRequestNo = p.c.outRequestNo,
                        StockName = p.c.stockName,
                        AvailableBeginTime = p.c.availableBeginTime.ObjToDate().ToString("yyyy-MM-dd HH:mm:ss"),
                        AvailableEndTime = p.c.availableEndTime.ObjToDate().ToString("yyyy-MM-dd HH:mm:ss"),
                        MaxCouponsPerUser = p.c.maxCouponsPerUser,
                        MaxCoupons = p.c.maxCoupons,
                        DistributedCoupons = p.c.distributedCoupons,
                        CouponAmount = p.c.couponAmount,
                        CouponId = u?.couponId,
                        OpenId = u?.openId,
                        CouponStatus = string.IsNullOrEmpty(u?.couponStatus) || u?.couponStatus == "SENDED" ? "可用" : u?.couponStatus == "USED" ? "已使用" : u?.couponStatus == "EXPIRED" ? "已过期" : "未知",
                        CouponOutRequestNo = u?.outRequestNo,
                        CouponSendDateTime = u?.addTime
                    }).Where(x => !string.IsNullOrEmpty(x.CouponOutRequestNo)).ToList();
                //获取会员信息
                var cardVoucher_userCoupons = cardVoucherUserCoupons.GroupJoin(posMembers, c => c.OpenId, u => u.openId,
                    (cv, uc) => new { cv, uc }).SelectMany(p => p.uc.DefaultIfEmpty(), (p, uc) => new MarketingFavorStockUserCouponsDto()
                    {
                        StockId = p.cv.StockId,
                        StockOutRequestNo = p.cv.StockOutRequestNo,
                        StockName = p.cv.StockName,
                        AvailableBeginTime = p.cv.AvailableBeginTime.ObjToDate().ToString("yyyy-MM-dd HH:mm:ss"),
                        AvailableEndTime = p.cv.AvailableEndTime.ObjToDate().ToString("yyyy-MM-dd HH:mm:ss"),
                        MaxCouponsPerUser = p.cv.MaxCouponsPerUser,
                        MaxCoupons = p.cv.MaxCoupons,
                        DistributedCoupons = p.cv.DistributedCoupons,
                        CouponAmount = p.cv.CouponAmount,
                        CouponId = p.cv.CouponId,
                        OpenId = p.cv.OpenId,
                        //CouponStatus = p.cv.CouponStatus,//由于任务会定时改状态，因此这里不需要另外处理
                        CouponStatus = p.cv.AvailableEndTime.ObjToDate().ToString("yyyy-MM-dd HH:mm:ss").CompareTo(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")) >= 0 ? p.cv.CouponStatus : "已过期",
                        CouponOutRequestNo = p.cv.CouponOutRequestNo,
                        CouponSendDateTime = p.cv.CouponSendDateTime,
                        MemberNo = uc?.No ?? "unknow",
                        MemberName = uc?.memberName ?? "unknow",
                        MemberTel = uc?.memberTel ?? "unknow"
                    }).ToList();

                //根据券状态过滤
                if (!string.IsNullOrEmpty(couponStatus))
                {
                    switch (couponStatus)
                    {
                        case "0":
                            cardVoucher_userCoupons = cardVoucher_userCoupons.Where(x => x.CouponStatus == "可用").ToList();
                            break;
                        case "1":
                            cardVoucher_userCoupons = cardVoucher_userCoupons.Where(x => x.CouponStatus != "可用").ToList();
                            break;
                        default:
                            break;
                    }
                }

                result = cardVoucher_userCoupons.Where(x => x.MemberTel != "unknow").OrderByDescending(x => x.StockId).ThenByDescending(x => x.CouponSendDateTime)?.ToList();

                //result = result.OrderByDescending(o => o.TopOrder).ThenByDescending(x => x.RecordDateTime)?.ToList();
                //总页数
                var pageCount = (result.Count() + pageSize - 1) / pageSize;
                //是否最后一页
                isLastPage = pageCount <= pageIndex;
                result = result.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
            }
            catch (Exception e)
            {
                errorMessage = e.Message;
                _logger.LogError(e.Message);
            }
            return (result, errorMessage, isLastPage);
        }
        #endregion

        #region 追加券详情
        /// <summary>
        /// 追加券详情
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<CardVoucherIntegralInfo[]> AttachCardVoucher(CardVoucherIntegralInfo[] data)
        {
            var db = await _cardVoucherIntegralRepository.GetDbContextAsync();

            await db.AttachData<CardVoucherInfo, CardVoucherIntegralInfo>(
                data, idGetter: x => x.cardVoucherId, action: (m, arr) =>
                {
                    //m.CardVoucherInfo = arr.FirstOrDefault();
                    m.CardVoucherInfo = arr.Where(x => DateTime.Parse(x.availableEndTime).ToString("yyyy-MM-dd HH:mm:ss").CompareTo(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")) >= 0).FirstOrDefault();
                });

            return data;
        }
        #endregion

        #region 会员卡相关

        #region 创建会员卡模板
        ///// <summary>
        ///// 创建会员卡模板
        ///// </summary>
        ///// <returns></returns>
        //public async Task<(string, string)> CreateMarketingMemberCardAsync(MarketingMemberCardCreateInputDto inputData)
        //{
        //    var stockId = "";
        //    var merchantId = inputData.MerchantId;
        //    var wechatTenpayClient = _wechatTenpayHttpClientFactory.Create(merchantId);
        //    var reqTempNo = await _noGeneratorService.GenerateGeneralNoAsync("_CV_");
        //    var outRequestNo = string.Concat(merchantId, reqTempNo, DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff"));//merchantId + "_TEST_ORN_" + DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff");
        //    var requestData = new CreateMarketingFavorStockRequest()
        //    {

        //    };

        //    var responseInfo = await wechatTenpayClient.executecreateme(requestData, cancellationToken: _accessor.HttpContext.RequestAborted);
        //    if (!responseInfo.IsSuccessful())
        //    {
        //        _logger.LogWarning(
        //            "创建代金券失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
        //            responseInfo.RawStatus, responseInfo.ErrorCode, responseInfo.ErrorMessage
        //        );
        //    }
        //    else
        //    {
        //        stockId = responseInfo.StockId;
        //        //创建成功则插入数据库

        //    }


        //    return (stockId, responseInfo.ErrorMessage);
        //}
        #endregion

        #endregion

        #endregion

        #region private method

        #region 保存代金券信息
        /// <summary>
        /// 保存代金券信息
        /// </summary>
        /// <param name="cardVoucherInfo"></param>
        /// <returns></returns>
        private async Task<bool> SaveCardVoucher(CardVoucherInfo cardVoucherInfo)
        {
            bool saveFlag = false;
            var stockId = cardVoucherInfo.stockId;
            if (string.IsNullOrEmpty(stockId))
                return saveFlag;
            try
            {
                //代金券插入数据库
                var db = await _cardVoucherRepository.GetDbContextAsync();
                var cardVoucher = await db.Set<CardVoucherInfo>().AsNoTracking().FirstOrDefaultAsync(x => x.stockId == stockId);
                if (cardVoucher == null)
                {
                    //如果批次号不存在则插入
                    var outRequestNo = string.Concat(stockId, DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff"));
                    cardVoucher = cardVoucherInfo;
                    cardVoucher.outRequestNo = outRequestNo;
                    _entityHelper.InitEntity(cardVoucher);
                    await _cardVoucherRepository.InsertAsync(cardVoucher, autoSave: true);
                    saveFlag = true;
                }
                else
                {
                    //批次号存在则更新
                    //状态
                    cardVoucher.cardStatus = cardVoucherInfo.cardStatus;
                    //已发券数量
                    cardVoucher.distributedCoupons = cardVoucherInfo.distributedCoupons;
                    cardVoucher.availableBeginTime = cardVoucherInfo.availableBeginTime;
                    cardVoucher.availableEndTime = cardVoucherInfo.availableEndTime;
                    cardVoucher.couponAmount = cardVoucherInfo.couponAmount;
                    cardVoucher.maxAmount = cardVoucherInfo.maxAmount;
                    cardVoucher.maxCoupons = cardVoucherInfo.maxCoupons;
                    cardVoucher.maxCouponsPerUser = cardVoucherInfo.maxCouponsPerUser;
                    cardVoucher.maxAmountByDay = cardVoucherInfo.maxAmountByDay;
                    cardVoucher.stockName = cardVoucherInfo.stockName;
                    cardVoucher.naturalPersonLimit = cardVoucherInfo.naturalPersonLimit;
                    cardVoucher.noCash = cardVoucherInfo.noCash;
                    cardVoucher.updateTime = DateTime.Now;
                    _entityHelper.SetUpdationInfo(cardVoucher);
                    await _cardVoucherRepository.UpdateAsync(cardVoucher, autoSave: true);
                    saveFlag = true;
                }
            }
            catch(Exception e)
            {
                _logger.LogError("存券失败。" + e.Message);
            }
            return saveFlag;
        }
        #endregion

        #region 发送积分兑换代金券消息通知
        private async Task<string> SendIntegralExchangeMessage(string openId, string msgContent)
        {
            var result = "";
            try
            {
                //发送消息的数据
                var messageData = new Dictionary<string, CgibinMessageTemplateSendRequest.Types.DataItem>();
                messageData.Add("first", new CgibinMessageTemplateSendRequest.Types.DataItem() { Value = "亲爱的会员，您已积分兑换成功", Color = "#173177" });
                messageData.Add("keyword1", new CgibinMessageTemplateSendRequest.Types.DataItem() { Value = "代金券" }/*{ Value = "积分兑换" }*/);
                messageData.Add("keyword2", new CgibinMessageTemplateSendRequest.Types.DataItem() { Value = msgContent });
                messageData.Add("keyword3", new CgibinMessageTemplateSendRequest.Types.DataItem() { Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") });
                messageData.Add("remark", new CgibinMessageTemplateSendRequest.Types.DataItem() { Value = "感谢您的支持" });

                var templateMsgSendData = new TemplateMsgSendDto()
                {
                    MessageType = 2,
                    OpenId = openId,
                    MessageItemDate = messageData
                };
                //请求数据
                result = await _templateMessageService.Send(templateMsgSendData);
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message);
            }
            return result;
        }
        #endregion

        #endregion
    }
}
